Carbon

     

Creating and Allocating a Thread

This section shows you how to create a pool of threads, allocate a thread from that pool, and get this thread to run. The code samples in this section are adapted from a sample application that addresses the classic computer science dining philosophers problem. This application uses a separate thread to control the display and movement of each philosopher icon as the philosophers move, one by one, into a dining room, pick up a fork eat, and then leave the room.

When your application launches, the Process Manager automatically creates the main, or application, thread. You are responsible for creating any additional threads. The main function is the entry point to the main thread. One of the features of the main thread is that it is the only thread from which you can properly call the Memory Manager MaxApplZone function to expand your application heap to its limit. You must call MaxApplZone before any other threads run.

Listing 1 shows the main function for an application, which calls subroutines that perform initializations and create and allocate threads. It also shows the application's event loop.

Listing 1  Setting up the main thread

void main()

{
    WindowPtr       appWindow;          
    MaxApplZone();                          /* Expand application heap */
    
    DoInitMac();                            /* Standard Macintosh 
                                                application initialization */
    DoCreateTPool();                        /* Create a pool of threads */
    
    appWindow = DoInitRooms();              /* Drawing initialization */
    DoInitPhilos(appWindow);                /* Initialize philosophers */
    DoSpawnThreads();                       /* Allocate new threads */
    MyEventLoop();                          /* Event handlers 
}
            ...
void MyEventLoop()
{
EventRecord         my_evt;
    short           got_evt = 0;
    OSErr           anError;
    WindowPtr       win;
    
    while( !gDone )
    {
        
        got_evt = WaitNextEvent(everyEvent, &my_evt, 
                                        kSleepTicks, nil);
        
        if ( got_evt )
        {
            switch( my_evt.what )
            {
                /* Case statements for each event */
            }
        }
        else
        {
            /* Draw window */
        }
        
        anError = YieldToAnyThread();
        if ( anError )
            DoHandlerError ("\pError in yielding from the main
                                 thread", 
                                 anError, kFatal);
    }
    /* Shutdown routines */
            ...
}

In Listing 1, the first thing the main function does, after declaring a window pointer variable, is to call the MaxApplZone function to extend the application heap. To be safe, this call comes before any of the initialization calls. It must come before any other thread runs in the application.

The main function calls two functions ( DoInitMac , and DoInitPhilos ) to perform various Macintosh and application-specific initializations. These functions are not of particular interest here, other than to show the order in which main calls them in relationship to MaxApplZone , so the code they contain is not shown here. The DoCreateTPool and DoSpawnThreads functions create a pool of threads and allocate threads from the pool, respectively. The next two sections show and describe the code for these functions.

Note that the main function contains the event loop for the application. While it is not required that the main thread handle all events, it is highly recommended that it do so. A characteristic of the main thread is that whenever an operating-system event is pending, the Thread Manager schedules the main thread at the next generic scheduling opportunity (that is, when a yield or other call causes a reschedule but does not specify a particular thread to schedule next), no matter where the main thread is in the scheduling queue. This characteristic of the main thread guarantees responsiveness to users if, as in the sample code, the main thread handles event-processing.

Listing 1 shows a skeletal view of MyEventLoop . It is a standard event loop, with a while loop and various case statements to handle the various possible Macintosh events. The main thread should make a yield call often enough to allow other threads an opportunity to run. Therefore, it calls the Thread Manager YieldToAnyThread function each time through the event loop.

Creating a Pool of Threads

Allocating a Thread


© 2000 Apple Computer, Inc. – (Last Updated 09 May 00)